package com.ch5;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPThreadServer {
  private int port = 7777; //服务器监听端口
  private ServerSocket serverSocket; //定义服务器套接字
  private ExecutorService executorService; //线程池
  private static final int POOL_SIZE = 10; //线程池大小

  public TCPThreadServer() throws IOException {
    serverSocket = new ServerSocket(port);
    //创建线程池
    executorService = Executors.newFixedThreadPool(POOL_SIZE);
    System.out.println("服务器启动监听在 " + port + " 端口");
  }

  private PrintWriter getWriter(Socket socket) throws IOException {
    //获得输出流缓冲区的地址
    OutputStream socketOut = socket.getOutputStream();
    //网络流写出需要使用flush，这里在PrintWriter构造方法中直接设置为自动flush
    return new PrintWriter(
            new OutputStreamWriter(socketOut, "utf-8"), true);
  }

  private BufferedReader getReader(Socket socket) throws IOException {
    //获得输入流缓冲区的地址
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(
            new InputStreamReader(socketIn, "utf-8"));
  }

  //多客户版本，使用线程池处理多个客户端连接
  public void service() {
    while (true) {
      Socket socket = null;
      try {
        //程序阻塞等待，监听并等待客户发起连接
        socket = serverSocket.accept();
        //将客户端连接交给线程池处理
        executorService.execute(new Handler(socket));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  public static void main(String[] args) throws IOException {
    new TCPThreadServer().service();
  }

  class Handler implements Runnable {
    private Socket socket;

    public Handler(Socket socket) {
      this.socket = socket;
    }

    @Override
    public void run() {
      //本地服务器控制台显示客户端连接的用户信息
      System.out.println("New connection accepted： " +
              socket.getInetAddress().getHostAddress());
      try {
        BufferedReader br = getReader(socket);//定义字符串输入流
        PrintWriter pw = getWriter(socket);//定义字符串输出流

        //客户端正常连接成功，则发送服务器欢迎信息，然后等待客户发送信息
        pw.println("From 服务器：欢迎使用本服务！");

        String msg = null;
        //此处程序阻塞，每次从输入流中读入一行字符串
        while ((msg = br.readLine()) != null) {
          //如果客户发送的消息为"bye"，就结束通信
          if (msg.trim().equalsIgnoreCase("bye")) {
            //向输出流中输出一行字符串,远程客户端可以读取该字符串
            pw.println("From 服务器：服务器已断开连接，结束服务！");
            System.out.println("客户端离开");
            break;//跳出循环读取
          }
          // 如果收到"来自教师服务器的连接"，回发1
          else if (msg.equals("来自教师服务器的连接")) {
            pw.println("1");
          }
          // 如果收到"教师服务器再次发送信息"，回发2
          else if (msg.equals("教师服务器再次发送信息")) {
            pw.println("2");
          }
          //向输出流中回传字符串,远程客户端可以读取该字符串
          else {
            pw.println("From 服务器：" + msg);
          }
        }
      } catch (IOException e) {
        e.printStackTrace();
      } finally {
        try {
          if (socket != null)
            socket.close(); //关闭 socket 连接及相关的输入输出流
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
}